package uit.edu.vn.portal.elearning.logic;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uit.edu.vn.portal.elearning.models.announcement.Announcement;
import uit.edu.vn.portal.elearning.models.assignment.Assignment;
import uit.edu.vn.portal.elearning.models.schedule.CalendarEvent;
import uit.edu.vn.portal.elearning.models.course.Site;
import uit.edu.vn.portal.elearning.models.course.Tool;
import uit.edu.vn.portal.elearning.support.WebServiceSupport;
import uit.edu.vn.portal.elearning.utils.XmlParser;


public class SakaiWSLogic {

	private String adminUsername;
	private String adminPassword;
	private String loginUrl;
	private String scriptUrl;
	private String serviceUrl;
	private String eid;
	
	// stores the admin session, not accessible
	private String session;

	private final String METHOD_LOGIN="login";
	private final String METHOD_GET_USER_ID="getUserId";
	private final String METHOD_CHECK_SESSION="checkSession";
	private final String METHOD_GET_ALL_SITES_FOR_USER="getAllSitesForUser";
	private final String METHOD_GET_PAGES_AND_TOOLS_FOR_SITE="getPagesAndToolsForSite";
	private final String METHOD_GET_ANNOUNCEMENTS_FOR_SITE="getAnnouncementsForSite";
	private final String METHOD_GET_SCHEDULESFORSITE = "getSchedulesForSite";
	private final String METHOD_GET_ASSIGNMENTSFORSITE = "getAssignmentsForSite";
	private final String METHOD_GET_PAGE_ID_CONTAINER = "getPageIdContainer";
	private final String METHOD_GET_SITE_TITLE = "getSiteTitle";
	private final String METHOD_GET_ALL_SITES_JOINABLE_FOR_USER = "getAllJoinableSitesForUser";
	private final String METHOD_ADD_USER_TO_SITE_WITH_ROLE = "addMemberToSiteWithRole";
	private final String METHOD_ADD_NEW_SITE = "addNewSite";
	private final String METHOD_ADD_NEW_PAGE_TO_SITE = "addNewPageToSite";
	private final String METHOD_ADD_NEW_TOOL_TO_PAGE = "addNewToolToPage";
	
	private static final Log log = LogFactory.getLog(SakaiWSLogic.class);
	
	/**
	 * Get the userId for a user.
	 * @return id or null if no response
	 */
	public String getRemoteUserIdForUser() {
		
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("eid", new HashMap<String,String>(){
			{
				put("value",getEid());
				put("type","string");
			}
		});
		
		return WebServiceSupport.call(getScriptUrl(), METHOD_GET_USER_ID, data);
	}
	
	public String getSiteTitle(final String siteid) {
		
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("eid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		return WebServiceSupport.call(getScriptUrl(), METHOD_GET_SITE_TITLE, data);
	}
	
	public String addNewSite(final String siteid, final String title, final String description, 
			final String shortdesc, final String iconurl, final String infourl, final String joinable, 
			final String joinerrole, final String published, final String publicview, final String skin, final String type){
		
			Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
			data.put("sessionid", new HashMap<String,String>(){
				{
					put("value",getSession());
					put("type","string");
				}
			});
			data.put("siteid", new HashMap<String,String>(){
				{
					put("value",siteid);
					put("type","string");
				}
			});
			data.put("title", new HashMap<String,String>(){
				{
					put("value",title);
					put("type","string");
				}
			});
			data.put("description", new HashMap<String,String>(){
				{
					put("value",description);
					put("type","string");
				}
			});
			data.put("shortdesc", new HashMap<String,String>(){
				{
					put("value",shortdesc);
					put("type","string");
				}
			});
			data.put("iconurl", new HashMap<String,String>(){
				{
					put("value",iconurl);
					put("type","string");
				}
			});
			data.put("infourl", new HashMap<String,String>(){
				{
					put("value",infourl);
					put("type","string");
				}
			});
			data.put("joinable", new HashMap<String,String>(){
				{
					put("value",joinable);
					put("type","string");
				}
			});
			data.put("joinerrole", new HashMap<String,String>(){
				{
					put("value",joinerrole);
					put("type","string");
				}
			});
			data.put("published", new HashMap<String,String>(){
				{
					put("value",published);
					put("type","string");
				}
			});
			data.put("publicview", new HashMap<String,String>(){
				{
					put("value",publicview);
					put("type","string");
				}
			});
			data.put("skin", new HashMap<String,String>(){
				{
					put("value",skin);
					put("type","string");
				}
			});
			data.put("type", new HashMap<String,String>(){
				{
					put("value",type);
					put("type","string");
				}
			});
			return WebServiceSupport.call(getServiceUrl(), METHOD_ADD_NEW_SITE, data);
	}
	
	public String addNewPageToSite(final String siteid,final String pagetitle,final int pagelayout){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		data.put("pagetitle", new HashMap<String,String>(){
			{
				put("value",pagetitle);
				put("type","string");
			}
		});
		
		data.put("pagelayout", new HashMap<String,String>(){
			{
				put("value",String.valueOf(pagelayout));
				put("type","string");
			}
		});
		
		return WebServiceSupport.call(getServiceUrl(), METHOD_ADD_NEW_PAGE_TO_SITE, data);
	}
	
	public String addNewToolToPage(final String siteid,final String pagetitle,final String tooltitle,final String toolid,final String layouthints){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		data.put("pagetitle", new HashMap<String,String>(){
			{
				put("value",pagetitle);
				put("type","string");
			}
		});
		
		data.put("tooltitle", new HashMap<String,String>(){
			{
				put("value",tooltitle);
				put("type","string");
			}
		});
		
		data.put("toolid", new HashMap<String,String>(){
			{
				put("value",toolid);
				put("type","string");
			}
		});
		
		data.put("layouthints", new HashMap<String,String>(){
			{
				put("value",layouthints);
				put("type","string");
			}
		});
		
		return WebServiceSupport.call(getScriptUrl(), METHOD_ADD_NEW_TOOL_TO_PAGE, data);
	}
	
	public String addMemberToSiteWithRole(final String siteid, final String userid, final String roleid){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		data.put("eid", new HashMap<String,String>(){
			{
				put("value",userid);
				put("type","string");
			}
		});
		
		data.put("roleid", new HashMap<String,String>(){
			{
				put("value",roleid);
				put("type","string");
			}
		});
		
		return WebServiceSupport.call(getScriptUrl(), METHOD_ADD_USER_TO_SITE_WITH_ROLE, data);
	}
	
	/**
	 * Get the XML for a list of all sites for a user, transformed to a List of Sites
	 * @return
	 */
	public List<Site> getAllSitesForUser() {
				
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("eid", new HashMap<String,String>(){
			{
				put("value",getEid());
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getScriptUrl(), METHOD_GET_ALL_SITES_FOR_USER, data);		
		
		return XmlParser.parseListOfSites(xml);
	}
	
	public List<Site> getAllJoinableSitesForUser(){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("eid", new HashMap<String,String>(){
			{
				put("value",getEid());
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getScriptUrl(), METHOD_GET_ALL_SITES_JOINABLE_FOR_USER, data);		
		log.info(xml);
		return XmlParser.parseListOfSites(xml);
	}
	/**
	 * Get the list of tools in a site.
	 * @param siteId	siteId
	 * @return
	 */
	public List<Tool> getToolsForSite(final String siteId) {
		
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		data.put("userid", new HashMap<String,String>(){
			{
				put("value",getEid());
				put("type","string");
			}
		});
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteId);
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getScriptUrl(), METHOD_GET_PAGES_AND_TOOLS_FOR_SITE, data);		

		return XmlParser.parseListOfPages(xml);
	}
	
	public List<Announcement> getAnnouncementsForSite(final String siteid){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});

		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getServiceUrl(), METHOD_GET_ANNOUNCEMENTS_FOR_SITE, data);		

		return XmlParser.parseListOfAnnouncements(xml);
	}
	
	public List<CalendarEvent> getSchedulesForSite(final String siteid){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getServiceUrl(), METHOD_GET_SCHEDULESFORSITE, data);		
		return XmlParser.parseListOfCalendarEvents(xml);
	}
	
	public List<Assignment> getAssignmentsForSite(final String siteid){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",getSession());
				put("type","string");
			}
		});
		
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		String xml = WebServiceSupport.call(getServiceUrl(), METHOD_GET_ASSIGNMENTSFORSITE, data);		
		//return xml;
		return XmlParser.parseListOfAssignments(xml);
	}
	
	public String getPageIdContainer(final String siteid, final String toolid){
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("siteid", new HashMap<String,String>(){
			{
				put("value",siteid);
				put("type","string");
			}
		});
		
		data.put("toolid", new HashMap<String,String>(){
			{
				put("value",toolid);
				put("type","string");
			}
		});
		
		String result = WebServiceSupport.call(getServiceUrl(), METHOD_GET_PAGE_ID_CONTAINER, data);		
		
		return result;
	}
	
	/**
	 * Get a new session for the admin user. Don't call this directly, use getSession() instead.
	 * @return
	 */
	private String getNewAdminSession() {
		
		String session = null;
		
		//setup data to send
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("id", new HashMap<String,String>(){
			{
				put("value",getAdminUsername());
				put("type","string");
			}
		});
		data.put("pw", new HashMap<String,String>(){
			{
				put("value",getAdminPassword());
				put("type","string");
			}
		});
		
		session = WebServiceSupport.call(getLoginUrl(), METHOD_LOGIN, data);
		
		//store locally
		setSession(session);
		
		//and return it
		return session;
	}
	
	/**
	 * Check the current session is still active. Don't call this directly, use getSession() instead.
	 * @return
	 */
	private boolean isSessionActive() {
		
		Map<String,Map<String,String>> data = new HashMap<String,Map<String,String>>();
		data.put("sessionid", new HashMap<String,String>(){
			{
				put("value",session);
				put("type","string");
			}
		});
		
		String results = WebServiceSupport.call(getScriptUrl(), METHOD_CHECK_SESSION, data);
		
		if(StringUtils.equals(results, session)) {
			return true;
		}
		
		return false;
	}
	
	
	
	/**
	 * Default no-arg constructor
	 */
	public SakaiWSLogic() {
		
	}
	

	public String getAdminUsername() {
		return adminUsername;
	}
	public void setAdminUsername(String adminUsername) {
		this.adminUsername = adminUsername;
	}
	public String getAdminPassword() {
		return adminPassword;
	}
	public void setAdminPassword(String adminPassword) {
		this.adminPassword = adminPassword;
	}
	public String getLoginUrl() {
		return loginUrl;
	}
	public void setLoginUrl(String loginUrl) {
		this.loginUrl = loginUrl;
	}
	public String getScriptUrl() {
		return scriptUrl;
	}
	public void setScriptUrl(String scriptUrl) {
		this.scriptUrl = scriptUrl;
	}
	public String getServiceUrl() {
		return serviceUrl;
	}
	public void setServiceUrl(String serviceUrl) {
		this.serviceUrl = serviceUrl;
	}
	public void setEid(String eid) {
		this.eid = eid;
	}
	public String getEid() {
		return eid;
	}

	
	
	/**
	 * Get local session, check it's still active, otherwise get a new one
	 * @return
	 */
	private String getSession() {
		
		if(StringUtils.isBlank(session)) {
			return getNewAdminSession();
		}
		
		if(!isSessionActive()){
			return getNewAdminSession();
		}
		
		return session;
	}
	private void setSession(String session) {
		this.session = session;
	}
}
